📝 我的笔记

还没有笔记

选中页面文字后点击「高亮」按钮添加

管道
COMS W3157
Borowski 博士

📜 原文
📖 逐步解释
∑ 公式拆解
💡 数值示例
⚠️ 易错点
📝 总结
🎯 存在目的
🧠 直觉心智模型
💭 直观想象

1管道
COMS W3157
Borowski 博士

1 什么是 IPC?

IPC 代表进程间通信。它是一组编程接口,允许进程之间进行协调活动。

2 Unix IPC

图 15.1 UNIX 系统 IPC 摘要

3 Unix 管道

管道是 UNIX 系统 IPC 最古老的形式,所有 UNIX 系统都提供。

管道有两个限制:

4 Shell 中的管道线

```

cat file.txt | sort | uniq > sorted_file.txt

```

cat 的输出成为 sort 的输入,sort 的输出成为 uniq 的输入。uniq 的输出被重定向到一个文件。

5 创建管道

```

#include

int pipe(int fd[2]);

```

通过 fd 参数返回两个文件描述符:

fd[1] 的输出是 fd[0] 的输入。

6 OS 提供的管道

\#include int pipe(int fd[2]);

通过 fd 参数返回两个文件描述符:

fd[1] 的输出是 fd[0] 的输入。

7 fork() 后的管道

正如我们刚刚所见,单个进程中的管道几乎无用。

通常,调用 pipe() 的进程会接着调用 fork(),从而在父进程和子进程之间创建一个 IPC 通道,反之亦然。

图 15.3 fork 后的半双工管道

8 半双工

读取进程应关闭 fd[1] 并使用 fd[0] 进行读取。写入进程应关闭 fd[0] 并使用 fd[1] 进行写入。

图 15.3 fork 后的半双工管道

图 15.4 从父进程到子进程的管道

9 规则

当管道的一端关闭时,适用两条规则。

  1. 如果我们从一个写入端已关闭的管道读取,则在所有数据都被读取后,read 返回 0 表示文件结束。

10 规则,续

  1. 如果我们向一个读取端已关闭的管道写入,则会生成 SIGPIPE 信号。如果我们忽略该信号或捕获它并从信号处理程序返回,write 返回 -1,并将 errno 设置为 EPIPE

11 示例代码

```

#include "apue.h"

int main(void) {

int n;

int fd[2];

pid_t pid;

char line[MAXLINE];

if (pipe(fd) < 0)

err_sys("pipe error");

if ((pid = fork()) < O) {

err_sys("fork error");

} else if (pid > 0) { / parent /

close(fd[0]);

write(fd[1], "hello world\n", 12);

} else { / child /

close(fd[1]);

n = read(fd[O], line, MAXLINE);

write(STDOUT_FILENO, line, n);

}

exit(O);

}

```

12 将 stdin/stdout 重定向到管道

为了将管道与已执行的进程一起使用,我们无法直接访问 pipe() 创建的文件描述符,我们必须使用 dup2() 函数,如下所示:

```

#include

int dup(int oldfd);

int dup2(int oldfd, int newfd);

```

dup() 系统调用创建一个文件描述符的副本。它使用最低编号的未使用描述符作为新描述符。

dup2() 系统调用与 dup() 类似,但它们之间的基本区别在于,dup2() 不使用最低编号的未使用文件描述符,而是使用用户指定的描述符编号。

13 管道示例

假设您想计算系统上运行的名为“kworker”的进程有多少。

shell 中,您可以设置以下命令管道:

ps -A | grep -i kworker | wc -l

要在 C 中实现这一点,会复杂得多。

14 C 程序的草图

声明 3 个 int[] 数组并在父进程中调用 pipe() 3 次。

调用 fork() 3 次。对于每个子进程:

在父进程中,从最后一个进程和父进程之间的管道的开放端读取。在屏幕上打印输出。

等待所有 3 个子进程执行完毕。

15 开放/关闭描述符图

现在研究 Canvas 中的 countprocess.c

16 popen()

```

FILE popen(const char command, const

char *type);

```

```

int pclose(FILE *stream);

```